package org.wizehack.mri.testSet;

import java.util.ArrayList;
import java.util.List;

import org.wizehack.mri.CoverageDataParser.Line;
import org.wizehack.mri.CoverageDataParser.SourceFile;
import org.wizehack.mri.exception.InvalidFileExtensionException;
import org.wizehack.mri.test.TestCase;
import org.wizehack.mri.test.TestSuite;
import org.wizehack.mri.testSet.Regions.Code;
import org.wizehack.mri.testSet.Regions.SrcFile;

public class MixedRegionbasedSelection extends TestCaseReductionExt {
	private static double TRESHOLD = 0.0;
	SimilaritybasedSelectionStrategy simStrategy;
	
	public MixedRegionbasedSelection(){
		super();	
	}
	
	@Override
	public List<TestSuite> select(List<TestSuite> testSuiteList) {
		
		List<TestSuite> tSuiteList = new ArrayList<TestSuite>();
		List<TestSuite> result = new ArrayList<TestSuite>();
		for(int i=0; i<testSuiteList.size(); i++){
			tSuiteList = this.createTestSuiteList(testSuiteList.get(i));
			for(int j=0; j<tSuiteList.size(); j++){
				TestSuite testSuite = tSuiteList.get(j);
				result.add(testSuite);
			}
		}
		
		return result;
	}

	@Override
	public List<TestSuite> createTestSuiteList(TestSuite testSuite) {
		simStrategy = new SimilaritybasedSelectionStrategy(TRESHOLD);

		simStrategy.setFailedCoverageFileList(this.getFailedCoverageFileList());
		simStrategy.setDirectory(this.getDirectory());
				
		List<TestSuite> similarityBasedTestSuiteList = simStrategy.createTestSuiteList(testSuite);
		List<TestSuite> filteredTestSuiteList = new ArrayList<TestSuite>();
		for(int i=0; i<similarityBasedTestSuiteList.size(); i++){
			TestSuite similarityBasedTestSuite = similarityBasedTestSuiteList.get(i);
			TestCase failedTestCase = this.getFailedTestCase(similarityBasedTestSuite);				
			List<SourceFile> mixedRegionSourceFileList = this.getMixedRegion(failedTestCase, similarityBasedTestSuite);
			
			TestSuite filteredTestSuite = this.mixedRegionbasedSelect(mixedRegionSourceFileList, similarityBasedTestSuite);
			System.out.println("---------------");

			filteredTestSuite.add(failedTestCase);
			filteredTestSuiteList.add(filteredTestSuite);
		}

		return filteredTestSuiteList;
	}
	
	public void exportTo(List<TestSuite> testSuiteList, String destDir, String dtdFile){
		try {
			simStrategy.exportTo(testSuiteList, destDir, dtdFile);
		} catch (InvalidFileExtensionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private TestSuite mixedRegionbasedSelect(List<SourceFile> mixedRegionSourceFileList, TestSuite testSuite){
		TestSuite tSuite = testSuite;

		List<String> mixedFileList = new ArrayList<String>();
		for(int i=0; i<mixedRegionSourceFileList.size(); i++){
			SourceFile mixedSourceFile = mixedRegionSourceFileList.get(i);
			mixedFileList.add(mixedSourceFile.getName());
		}
		
		for(int i=0; i<testSuite.size(); i++){
			TestCase testCase = testSuite.get(i);
			List<SourceFile> covFileList = testCase.getCoverage();
			boolean hasMixedFile = false;
			
			for(int j=0; j<covFileList.size(); j++){
				SourceFile covFile = covFileList.get(j);
				
				if(mixedFileList.contains(covFile.getName())){
					hasMixedFile = true;
					
					List<Integer> lineNumberList = new ArrayList<Integer>();
					for(int k=0; k<covFile.size(); k++){
						int lineNumber = covFile.get(k).getLineNumber();
						lineNumberList.add(lineNumber);
					}
					
					boolean hasSameLine = false;
					for(int k=0; k<mixedRegionSourceFileList.size(); k++){
						SourceFile mixedSourceFile = mixedRegionSourceFileList.get(k);
						
						for(int l=0; l<mixedSourceFile.size(); l++){
							if(lineNumberList.contains(mixedSourceFile.get(l).getLineNumber())){
								hasSameLine = true;
							}
						}
					}
					
					if(hasSameLine == false){
						System.out.println("does not have mixed Line: " + testCase.getCoverageLocation());
						tSuite.remove(testCase);
						i--;
					}
					
				}// end if
				
			}//end for j
			
			if(hasMixedFile == false){
				System.out.println("does not have mixed file: " + testCase.getCoverageLocation());
				tSuite.remove(testCase);
				i--;
			}
			
		}//end for i
		
		return tSuite;
	}
	
	private TestCase getFailedTestCase(TestSuite testSuite){
		TestCase failedTestCase = null;
		for(int i=0; i<testSuite.size(); i++){
			if(testSuite.get(i).isPassed() == false){
				failedTestCase = testSuite.get(i);
				break;
			}
		}
		
		return failedTestCase;
	}
	
	private List<SourceFile> getMixedRegion(TestCase failedTestCase, TestSuite testSuite){

		List<SourceFile> failedCoverage = failedTestCase.getCoverage();		
		TestSuite tSuite = this.removeFailedTestCase(testSuite);

		Regions regions = this.getRegtions(failedCoverage, tSuite);
		Regions mixedRegion = regions.getMixedRegion(tSuite.size());
		
		List<SourceFile> mixedRegionSourceFileList = new ArrayList<SourceFile>();
		
		for(int i=0; i<mixedRegion.fileList.size(); i++){
			SourceFile sourceFile = new SourceFile();
			String fileName = mixedRegion.fileList.get(i).fileName;
			sourceFile.setName(fileName);

			SrcFile srcFile = mixedRegion.fileList.get(i);
			
			for(int j=0; j<srcFile.codeList.size(); j++){
				int lineNumber = srcFile.codeList.get(j).number;
				Line line = new Line();
				line.setLineNumber(lineNumber);
				line.setCovered(true);
				sourceFile.add(line);
			}
			
			mixedRegionSourceFileList.add(sourceFile);
		}
		
		return mixedRegionSourceFileList;
	}
	

	/**
	 * 각 소스코드의 라인마다 반복되는 횟수를 regions객체에 저장한다. 
	 * @param failedCoverage
	 * @param tSuite
	 * @return
	 */
	private Regions getRegtions(List<SourceFile> failedCoverage, TestSuite tSuite) {
		Regions regions = Regions.getInstance();
				
		for(int i=0; i<failedCoverage  .size(); i++){
			SrcFile failedSrcFile = regions.getNewSrcFileInstance();
			
			SourceFile failedSourceFile = failedCoverage.get(i);
			String failedFileName = failedSourceFile.getName();
			failedSrcFile.fileName = failedFileName;
			
			regions.fileList.add(failedSrcFile);
			
			for(int j=0; j<failedSourceFile.size(); j++){
				int failedLinenumber = failedSourceFile.get(j).getLineNumber();
				Code failedCode = regions.getCodeNewInstance();
				failedCode.number = failedLinenumber;
				failedCode.coveredCount = 0;
				failedSrcFile.codeList.add(failedCode);
				
			}
			
			for(int j=0; j<tSuite.size(); j++){
				TestCase testCase = tSuite.get(j);				
				for(int k=0; k<testCase.getCoverage().size(); k++){
					SourceFile sourceFile = testCase.getCoverage().get(k);
					
					if(sourceFile.getName().equals(failedFileName)){
												
						for(int l=0; l<sourceFile.size(); l++){
							int lineNumber = sourceFile.get(l).getLineNumber();
							
							for(int m=0; m<failedSrcFile.codeList.size(); m++){
								
								if(failedSrcFile.codeList.get(m).number == lineNumber){
									failedSrcFile.codeList.get(m).increaseCount();
									break;
								}
							}
						} //end for l
						
						break; //for performance
					}//end if
				}// end for k
			}//end for j
				
		}//end for i
		
		return regions;
	}
	
	private TestSuite removeFailedTestCase(TestSuite testSuite){
		
		TestSuite tSuite = testSuite;
		for(int i=0; i<testSuite.size(); i++){
			
			TestCase testCase = testSuite.get(i);
			if(testCase.isPassed() == false){
				tSuite.remove(testCase);
				break;
			}
		}
		
		return tSuite;
	}		
	
}
